package cn.larry.tools.easypay.utils;

import cn.larry.tools.cons.Constants;
import cn.larry.tools.easypay.bean.EasyPayBean;
import cn.larry.tools.http.HttpTool;
import cn.larry.tools.md5.Md5Tool;
import cn.larry.tools.string.StringTool;
import cn.larry.tools.time.TimeTool;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;

/**
 * Larry
 * 2021/7/21 15:43
 * 易生支付·微收单·工具类
 *
 * @Version 1.0
 */
@Slf4j
public class EasppayUtil {

    private String easypay_payurl;
    private String easypay_channelid;
    private String easypay_merid;
    private String easypay_termid;
    private String easypay_signkey;
    private String easypay_paynotify;

    /**
     * 针对应答报文是否进行验签
     */
    private boolean easypayRespVerifySign;

    public EasppayUtil(EasyPayBean easyPayBean) {
        this.easypay_payurl = easyPayBean.getPayurl();
        this.easypay_channelid = easyPayBean.getChannelid();
        this.easypay_merid = easyPayBean.getMerid();
        this.easypay_termid = easyPayBean.getTermid();
        this.easypay_signkey = easyPayBean.getSignkey();
        this.easypay_paynotify = easyPayBean.getPaynotify();
    }

    public EasppayUtil(String easypayPayurl,
                       String easypayChannelid,
                       String easypayMerid,
                       String easypayTermid,
                       String easypaySignkey,
                       String easypayPaynotify) {

        this.easypay_payurl = easypayPayurl;
        this.easypay_channelid = easypayChannelid;
        this.easypay_merid = easypayMerid;
        this.easypay_termid = easypayTermid;
        this.easypay_signkey = easypaySignkey;
        this.easypay_paynotify = easypayPaynotify;

    }


    /**
     * 微信小程序预下单接口
     *
     * @param tradeamt   订单金额（分）
     * @param tradetrace 请求单号
     * @param openid     微信用户openid
     * @param body
     * @return
     */
    public JSONObject pay(String tradeamt, String tradetrace, String openid, String body) throws Exception {
        JSONObject reqJson = new JSONObject();
        reqJson.put("channelid", easypay_channelid);
        reqJson.put("merid", easypay_merid);
        reqJson.put("termid", easypay_termid);

        reqJson.put("opt", "wxPreOrder");
        reqJson.put("tradetype", "JSAPI");

        reqJson.put("notifyurl", easypay_paynotify);
        reqJson.put("tradetrace", tradetrace);
        reqJson.put("body", body);
        reqJson.put("openid", openid);
        reqJson.put("tradeamt", tradeamt);
        reqJson.put("terminalinfo", "{\"terminalip\":\"127.0.0.1\"}");
        String sign = getSign(easypay_signkey, reqJson);
        reqJson.put("sign", sign);

        String respBody = HttpTool.send(easypay_payurl, reqJson, "UTF-8");
        log.info("支付渠道应答报文：{}", respBody);
        verifySign(respBody);

        return JSONObject.parseObject(respBody);
    }

    /**
     * （应"59号文改造"，增加IP字段上送）
     *
     * @param tradeamt
     * @param tradetrace
     * @param openid
     * @param terminalip
     * @param body
     * @return
     */
    public JSONObject pay(String tradeamt, String tradetrace, String openid, String terminalip, String body) throws Exception {
        if (StringTool.isBlank(terminalip))
            terminalip = "192.168.1.1";

        JSONObject reqJson = new JSONObject();
        reqJson.put("channelid", easypay_channelid);
        reqJson.put("merid", easypay_merid);
        reqJson.put("termid", easypay_termid);

        reqJson.put("opt", "wxPreOrder");
        reqJson.put("tradetype", "JSAPI");

        reqJson.put("notifyurl", easypay_paynotify);
        reqJson.put("tradetrace", tradetrace);
        reqJson.put("body", body);
        reqJson.put("openid", openid);
        reqJson.put("tradeamt", tradeamt);
        reqJson.put("terminalinfo", "{\"terminalip\":\"" + terminalip + "\"}");
        String sign = getSign(easypay_signkey, reqJson);
        reqJson.put("sign", sign);

        String respBody = HttpTool.send(easypay_payurl, reqJson, "UTF-8");
        log.info("支付渠道应答报文：{}", respBody);
        verifySign(respBody);

        return JSONObject.parseObject(respBody);
    }

    public String payToPrepayid(String tradeamt, String tradetrace, String openid, String body) throws Exception {
        JSONObject jsonObject = pay(tradeamt, tradetrace, openid, body);
//        log.info("支付渠道应答报文：{}", jsonObject);
//        String resultcode = jsonObject.getString("resultcode");
        return jsonObject.getString("prepayid");
    }

    public String payToPrepayid(String tradeamt, String tradetrace, String openid, String terminalip, String body) throws Exception {
        JSONObject jsonObject = pay(tradeamt, tradetrace, openid, terminalip, body);
//        log.info("支付渠道应答报文：{}", jsonObject);
//        String resultcode = jsonObject.getString("resultcode");
        return jsonObject.getString("prepayid");
    }


    /**
     * 交易查询
     *
     * @param tradetrace 原交易请求单号
     * @return
     */
    public JSONObject query(String tradetrace) throws Exception {
        JSONObject reqJson = new JSONObject();
        reqJson.put("channelid", easypay_channelid);
        reqJson.put("merid", easypay_merid);
        reqJson.put("termid", easypay_termid);

        reqJson.put("opt", "tradeQuery");

        reqJson.put("tradetrace", tradetrace);
        String sign = getSign(easypay_signkey, reqJson);
        reqJson.put("sign", sign);

        String respBody = HttpTool.send(easypay_payurl, reqJson, "UTF-8");
        verifySign(respBody);

        return JSONObject.parseObject(respBody);

    }

    /**
     * 交易撤销（仅对当日交易可以撤销，日切时间为渠道服务器的00:00）
     * （以下2个字段2选一，都上送以'oritradetrace'为准）
     *
     * @param oritradetrace 原交易请求单号
     * @param oriwtorderid  原交易的易生订单号
     * @return
     */
    public JSONObject cancel(String oritradetrace, String oriwtorderid) throws Exception {
        JSONObject reqJson = new JSONObject();
        reqJson.put("channelid", easypay_channelid);
        reqJson.put("opt", "cancel");
        reqJson.put("merid", easypay_merid);
        reqJson.put("termid", easypay_termid);
        reqJson.put("tradetrace", System.currentTimeMillis() + "_" + TimeTool.getNowTime(Constants.COMMON_TIME_FORMAT_yyyyMMddHHmmss));//商户订单号
        reqJson.put("oritradetrace", oritradetrace);//商户订单号
        reqJson.put("oriwtorderid", oriwtorderid);//交易

        String sign = getSign(easypay_signkey, reqJson);
        reqJson.put("sign", sign);

        String respBody = HttpTool.send(easypay_payurl, reqJson, "UTF-8");
        verifySign(respBody);

        return JSONObject.parseObject(respBody);
    }

    public String getSign(String key, Map<String, String> map) {
        ArrayList<String> list = new ArrayList<String>();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (!"sign".equals(entry.getKey()) && StringTool.isNotBlank(entry.getValue())) {
                list.add(entry.getKey() + "=" + entry.getValue() + "&");// key=value+
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + key;
        try {
//            System.out.println("md5之前：\n"+result);
            result = new Md5Tool().encrypt32ToUpperCase32(result, "UTF-8");
        } catch (Exception e) {
            log.error("报文签名异常", e);
        }
        return result;
    }

    public String getSign(String key, JSONObject jsonObject) {
        ArrayList<String> list = new ArrayList<String>();
        for (String jsonKey : jsonObject.keySet()) {
            if (!"sign".equals(jsonKey) && StringTool.isNotBlank(jsonObject.get(jsonKey) == null ? null : jsonObject.get(jsonKey).toString())) {
                list.add(jsonKey + "=" + jsonObject.getString(jsonKey) + "&");// key=value+
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + key;
        try {
//            System.out.println("md5之前：\n"+result);
            result = new Md5Tool().encrypt32ToUpperCase32(result, "UTF-8");
        } catch (Exception e) {
            log.error("报文签名异常", e);
        }
        return result;
    }


    public static final ObjectMapper mapper = new ObjectMapper();

    /**
     * 验签
     * @param body
     * @return
     */
//    @Async
    public boolean verifySign(String body) {
        if(!easypayRespVerifySign)
            return true;

        Boolean verifyFlag = false;
        try {
            Map<String, String> reqMap = mapper.readValue(body, Map.class);
            String respSign = reqMap.get("sign");
            String sign = getSign(easypay_signkey, reqMap);
            if (respSign.equals(sign))
                verifyFlag = true;
        } catch (Exception e) {
            log.error("验证签名异常", e);
        }
        log.info("验签结果：{}", verifyFlag);
        return verifyFlag;
    }

    public JSONObject getSign(String channelKey) throws Exception {
        JSONObject reqJson = new JSONObject();
        reqJson.put("channelid", easypay_channelid);
        reqJson.put("opt", "getSign");

        String sign = getSign(channelKey, reqJson);
        reqJson.put("sign", sign);

        String respBody = HttpTool.send(easypay_payurl, reqJson, "UTF-8");
        verifySign(respBody);

        return JSONObject.parseObject(respBody);
    }

    public boolean isEasypayRespVerifySign() {
        return easypayRespVerifySign;
    }

    public void setEasypayRespVerifySign(boolean easypayRespVerifySign) {
        this.easypayRespVerifySign = easypayRespVerifySign;
    }

}
